package game.targets.input;

import game.targets.Constants;
import game.targets.Locator;
import game.targets.MathFuncs;
import game.targets.RayCallback;
import game.targets.observer.Event;
import game.targets.room.Room;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.bullet.collision.ClosestRayResultCallback;

public class InputHandler implements InputProcessor, Constants {

	public int rotateButton = Buttons.LEFT;
	public int chargeButton = Buttons.RIGHT;

	private Room room;
	private CameraInputController controller;
	private boolean charging;
	private int pointerCharge;
	private int pointerMove;
	private float prevX, prevY;
	private int button;
	private float xAngle, yAngle;
	private Vector3 selection;
	private PerspectiveCamera camera;
	private RayCallback rayCallback;
	private Vector3 tmpV1, target;

	public InputHandler(Room room, CameraInputController controller, PerspectiveCamera camera, RayCallback rayCallback) {
		this.room = room;
		this.controller = controller;
		this.camera = camera;
		charging = false;
		pointerCharge = -1;
		pointerMove = -1;
		prevX = Gdx.graphics.getWidth() / 2;
		prevY = Gdx.graphics.getHeight() / 2;
		button = -1;
		xAngle = 0;
		yAngle = 0;
		selection = new Vector3();
		this.rayCallback=rayCallback;
		tmpV1=new Vector3();
		target=new Vector3();
	}

	@Override
	public boolean keyDown(int keycode) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean keyUp(int keycode) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean keyTyped(char character) {
		//Gdx.app.exit();
		return false;
	}

	@Override
	public boolean touchDown(int screenX, int screenY, int pointer, int button) {
		// powerup shot
		if (button == chargeButton /*
									 * && screenY > Gdx.graphics.getHeight() *
									 * 0.80f
									 */) {
			// controller.cancel();
			room.getSubject().notify(null, Event.EVENT_CHARGING_SHOT);
			charging = true;
			this.button = button;
		}
		// aim shot
		else {
			this.button = button;
			// uses the camera controller
		}
		return false;
	}

	ClosestRayResultCallback RayCallback(Vector3 Start, Vector3 End) {
		return null;

	}

	@Override
	public boolean touchUp(int screenX, int screenY, int pointer, int button) {
		charging = false;
		selection.x = Gdx.graphics.getWidth()/2;
		selection.y = Gdx.graphics.getHeight()/2;
		selection.z = 1;
		camera.unproject(selection);
		rayCallback.setPositions(camera.position, selection);
		Locator.getWorld().rayTest(camera.position, selection, rayCallback);
		rayCallback.clear();
		if(rayCallback.hasHit()){
			
		}
		if (button == chargeButton && charging) {
		}
		if (button == pointerMove) {
		}
		room.getSubject().notify(null, Event.EVENT_RELEASE_SHOT);
		return false;
	}
	
	@Override
	public boolean touchDragged(int screenX, int screenY, int pointer) {
		// powerup shot
		if (button == chargeButton /*
									 * && screenY > Gdx.graphics.getHeight() *
									 * 0.80f
									 */) {
			// controller.cancel();
		}
		// aim shot
		else if (button == rotateButton) {
			final float deltaX = (screenX - prevX) / Gdx.graphics.getWidth();
			final float deltaY = (prevY - screenY) / Gdx.graphics.getHeight();
			prevX = screenX;
			prevY = screenY;
			float calcXAngle = -deltaX * camera.fieldOfView;
			float calcYAngle = deltaY * Room.MAX_BOW_VIEW_HEIGHT_DEGREES;

			if (xAngle <= Room.MAX_BOW_VIEW_WIDTH_DEGREES && xAngle >= -Room.MAX_BOW_VIEW_WIDTH_DEGREES) {
				room.getBow().rotate(Vector3.Y, calcYAngle);
			}
			if (yAngle <= Room.MAX_BOW_VIEW_HEIGHT_DEGREES && yAngle >= -Room.MAX_BOW_VIEW_HEIGHT_DEGREES) {
				room.getBow().rotate(Vector3.Z, calcXAngle);
			}
			tmpV1.set(camera.direction).crs(camera.up).y = 0f;
			camera.rotateAround(target, tmpV1.nor(), calcYAngle);
			camera.rotateAround(target, Vector3.Y, calcXAngle);
			camera.update();
			xAngle += calcXAngle;
			yAngle += calcYAngle;
		}

		return false;
	}

	@Override
	public boolean mouseMoved(int screenX, int screenY) {
		final float deltaX = (screenX - prevX) / Gdx.graphics.getWidth();
		final float deltaY = (prevY - screenY) / Gdx.graphics.getHeight();
		prevX = screenX;
		prevY = screenY;

		float calcXAngle = -deltaX * camera.fieldOfView;
		float calcYAngle = deltaY * Room.MAX_BOW_VIEW_HEIGHT_DEGREES;

		if (xAngle <= Room.MAX_BOW_VIEW_WIDTH_DEGREES && xAngle >= -Room.MAX_BOW_VIEW_WIDTH_DEGREES) {
			room.getBow().rotate(Vector3.Y, calcYAngle);
		}
		if (yAngle <= Room.MAX_BOW_VIEW_HEIGHT_DEGREES && yAngle >= -Room.MAX_BOW_VIEW_HEIGHT_DEGREES) {
			room.getBow().rotate(Vector3.Z, calcXAngle);
		}
		//rotate camera
		tmpV1.set(camera.direction).crs(camera.up).y = 0f;
		camera.rotateAround(target, tmpV1.nor(), calcYAngle);
		camera.rotateAround(target, Vector3.Y, calcXAngle);
		camera.update();
		
		xAngle += calcXAngle;
		yAngle += calcYAngle;

		return false;
	}

	@Override
	public boolean scrolled(int amount) {
		// TODO Auto-generated method stub
		return false;
	}

}
